package com.xyzwps.orm.testcase;

import com.xyzwps.orm.exception.NoSuchTagException;
import com.xyzwps.orm.exception.TagDuplicateException;
import com.xyzwps.orm.model.Tag;
import com.xyzwps.orm.repository.TagRepository;

import java.util.Objects;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;

public class TagRepositoryCase {

    private final TagRepository tagRepository;

    public TagRepositoryCase(TagRepository tagRepo) {
        this.tagRepository = Objects.requireNonNull(tagRepo);
    }

    public void caseInsertAndGetOk() {
        var tag = new Tag();
        tag.setTagName("t1");
        tag.setUserId(123);

        var tagId = tagRepository.insert(tag);

        var $pTag = tagRepository.selectByTagId(tagId);
        assertTrue($pTag.isPresent());

        var pTag = $pTag.get();
        assertEquals(pTag.getTagId(), tagId);
        assertEquals(pTag.getTagName(), "t1");
        assertEquals(pTag.getUserId(), 123);

        assertTrue(tagRepository.selectByTagId(tagId * 100000).isEmpty());
    }

    public void caseInsertTagDuplicate() {
        var tag = new Tag();
        tag.setTagName("t1");
        tag.setUserId(123);

        tagRepository.insert(tag);

        var ex = assertThrows(TagDuplicateException.class, () -> {
            var newTag = new Tag();
            newTag.setTagName("t1");
            newTag.setUserId(123);
            tagRepository.insert(newTag);
        });
        assertEquals(ex.getMessage(), "标签 <t1> 重复");
    }

    public void caseUpdateOk() {
        var tag = new Tag();
        tag.setTagName("t2");
        tag.setUserId(123);

        var tagId = tagRepository.insert(tag);
        var $pTag = tagRepository.selectByTagId(tagId);
        assertTrue($pTag.isPresent());

        var pTag = $pTag.get();
        assertEquals(pTag.getTagId(), tagId);
        assertEquals(pTag.getTagName(), "t2");
        assertEquals(pTag.getUserId(), 123);

        pTag.setUserId(234);
        pTag.setTagName("T2");

        tagRepository.update(pTag);

        $pTag = tagRepository.selectByTagId(tagId);
        assertTrue($pTag.isPresent());

        pTag = $pTag.get();
        assertEquals(pTag.getTagId(), tagId);
        assertEquals(pTag.getTagName(), "T2");
        assertEquals(pTag.getUserId(), 234);
    }

    public void caseUpdateTagDuplicate() {
        var tag0 = new Tag();
        tag0.setTagName("t1");
        tag0.setUserId(123);
        tagRepository.insert(tag0);

        var tag = new Tag();
        tag.setTagName("t2");
        tag.setUserId(123);
        var tagId= tagRepository.insert(tag);
        var $pTag = tagRepository.selectByTagId(tagId);
        assertTrue($pTag.isPresent());
        var pTag = $pTag.get();
        pTag.setTagName("t1");

        var ex = assertThrows(TagDuplicateException.class, () -> tagRepository.update(pTag));
        assertEquals(ex.getMessage(), "标签 <t1> 重复");
    }

    public void caseUpdateNonExistedTag() {
        var tag = new Tag();
        tag.setTagName("t2");
        tag.setUserId(123);
        tag.setTagId(12345678);
        tagRepository.update(tag);
        assertTrue(tagRepository.selectByTagId(tag.getTagId()).isEmpty());
    }

    public void caseDeleteExistedTag() {
        var tag = new Tag();
        tag.setTagName("t2");
        tag.setUserId(123);

        var tagId = tagRepository.insert(tag);
        var $pTag = tagRepository.selectByTagId(tagId);
        assertTrue($pTag.isPresent());

        tagRepository.delete(tagId);

        $pTag = tagRepository.selectByTagId(tagId);
        assertTrue($pTag.isEmpty());
    }

    public void caseDeleteNonExistedTag() {
        tagRepository.delete(12345678);
    }

    public void caseSelectAllForUser() {
        final int UID = 1234;
        assertTrue(tagRepository.selectAllForUser(UID).isEmpty());

        for (int i = 1; i < 15; i++) {
            var tag = new Tag();
            tag.setUserId(UID);
            tag.setTagName("T-" + i);
            tagRepository.insert(tag);

            var tags = tagRepository.selectAllForUser(UID);
            assertEquals(tags.size(), i);
            assertEquals(tags.stream().map(Tag::getTagName).collect(Collectors.toSet()).size(), i);
        }
    }
}
